package com.zzf.concurrent.example.design.pattern.two.phase.termination;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author GaoFeng2017
 * @date 2019/9/9 20:55
 */
@Slf4j
public class ChatServer extends Thread {

    /** 端口号 */
    private int port;
    /** 默认端口号 */
    private final static int DEFAULT_PORT = 8090;
    /** 服务端socket，接收客户端发送的请求 */
    private ServerSocket serverSocket;
    /** 标识，代表服务端是否关闭 */
    private volatile boolean isClosed;
    /** 客户端socket列表 */
    private List<ClientSocketHandler> clientSockets;
    /** 线程池 */
    private ExecutorService executorService = Executors.newFixedThreadPool(10);

    public ChatServer() {
        this(DEFAULT_PORT);
    }

    public ChatServer(int port) {
        this.port = port;
        this.isClosed = false;
        this.clientSockets = new LinkedList<>();
    }

    @Override
    public void run() {
        try {
            this.serverSocket = new ServerSocket(this.port);
            log.info("server socket is start.");
            while (!isClosed) {
                Socket socket = serverSocket.accept();
                log.info("socket connect success -> {}", socket.getPort());
                ClientSocketHandler handler = new ClientSocketHandler(socket);
                executorService.submit(handler);
                clientSockets.add(handler);
            }
        } catch (IOException e) {
            log.error("socket happened io exception", e);

        } finally {
            this.dispose();
        }
    }

    private void dispose() {
        log.info("server socket resource will be release.");
        this.shutdown();
    }

    public void shutdown() {
        this.clientSockets.forEach(ClientSocketHandler::stop);
        this.isClosed = true;
        this.executorService.shutdown();
        try {
            this.serverSocket.close();
        } catch (IOException e) {
            log.error("fail to close server socket", e);
        }
    }
}
